package fun.codedesign.yinxue.text.panel;

import fun.codedesign.yinxue.text.service.impl.CacheTipService;
import fun.codedesign.yinxue.text.service.TipService;
import fun.codedesign.yinxue.util.FileUtil;
import fun.codedesign.yinxue.util.LogUtil;
import fun.codedesign.yinxue.util.StringUtil;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.List;

/**
 * 文本+滚动条
 *
 * @author zengjian
 * @create 2018-03-28 11:06
 * @since 1.0.0
 */
public class EditPanel extends JScrollPane {

    private JTextArea textArea = new JTextArea();

    public JPopupMenu tipMenu;
    public JPopupMenu rightClickMenu;

    public Clipboard clipboard;

    public EditPanel() {
        super(VERTICAL_SCROLLBAR_ALWAYS, HORIZONTAL_SCROLLBAR_AS_NEEDED);
        textArea.setLineWrap(true);
        setViewportView(textArea);
        getVerticalScrollBar().setUnitIncrement(20);
        textArea.setFont(new Font("微软雅黑", Font.PLAIN, 16));

        tipMenu = new JPopupMenu();

        rightClickMenu = new JPopupMenu();

        clipboard = this.getToolkit().getSystemClipboard();

        JMenuItem copy = new JMenuItem("复制");
        JMenuItem cut = new JMenuItem("剪切");
        JMenuItem v = new JMenuItem("粘贴");
        copy.addActionListener(e -> {
            copy();
        });

        cut.addActionListener(e -> {
            cut();
        });

        v.addActionListener(e -> {
            v();
        });

        rightClickMenu.add(copy);
        rightClickMenu.add(cut);
        rightClickMenu.add(v);

        // 输入法监听器
//        textArea.addInputMethodListener(new InputMethodListener() {
//            @Override
//            public void inputMethodTextChanged(InputMethodEvent event) {
//                System.out.println(event);
//            }
//
//            @Override
//            public void caretPositionChanged(InputMethodEvent event) {
//                System.out.println(event);
//
//            }
//        });

        textArea.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                int x = e.getX();
                int y = e.getY();
                if (e.getButton() == MouseEvent.BUTTON3) {
                    rightClickMenu.show(textArea, x, y);
                }
            }
        });

        TipService tipService = new CacheTipService();

        textArea.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                String changeText = "";
                int offset = e.getOffset();
                int length = e.getLength();
                try {
                    // TODO 空格所在的地方
                    String currentStr = e.getDocument().getText(offset, length);
                    if (offset != 0 && !" ".equals(currentStr) && !currentStr.endsWith("\n")) {
                        while (true) {
                            String s = e.getDocument().getText(offset, 1);
                            // TODO 寻找截止符，如 ; 空格 换行 标点符号等
                            if (!" ".equals(s) && !"\n".equals(s)) {
                                offset = offset - 1;
                                length = length + 1;
                            } else {
                                // 截取掉 截止符
                                offset = offset + 1;
                                break;
                            }
                        }
                    }
                    changeText = e.getDocument().getText(offset, length);
                } catch (BadLocationException ex) {
                    ex.printStackTrace();
                }
                showPopTipsForInsert(changeText, offset);
            }


            @Override
            public void removeUpdate(DocumentEvent e) {
                if (e.getOffset() == 0) {
                    return;
                }
                String changeText = "";
                // 删除偏移量的前一个
                int offset = e.getOffset() - 1;
                int length = e.getLength();
                try {
                    // TODO 空格所在的地方,
                    String currentStr = e.getDocument().getText(offset, length);
                    if (offset != 0 && !" ".equals(currentStr) && !currentStr.endsWith("\n")) {
                        while (true) {
                            String s = e.getDocument().getText(offset, 1);
                            // TODO 寻找截止符，如 ; 空格 换行 标点符号等
                            if (!" ".equals(s) && !"\n".equals(s)) {
                                offset = offset - 1;
                                length = length + 1;
                            } else {
                                // 截取掉 截止符
                                offset = offset + 1;
                                break;
                            }
                        }
                    }
                    changeText = e.getDocument().getText(offset, length);
                } catch (BadLocationException ex) {
                    ex.printStackTrace();
                }
                showPopTipsForDelete(changeText, offset);
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                System.out.println(e.toString());
            }

            private void showPopTipsForInsert(String changeText, int offset) {
                // 非全文加载时显示提示
                if (offset != 0 || !changeText.startsWith(" ")) {
                    Rectangle rectangle = null;
                    try {
                        // 如果在边缘处，会报错
                        rectangle = textArea.modelToView(textArea.getCaretPosition() + 1);
                    } catch (BadLocationException ex) {
                        ex.printStackTrace();
                        LogUtil.error(EditPanel.class, "", ex);
                        try {
                            rectangle = textArea.modelToView(textArea.getCaretPosition());
                        } catch (BadLocationException e) {
                            e.printStackTrace();
                        }
                    }
                    if (rectangle != null) {
                        tipMenu.removeAll();
                        if ("\n".equals(changeText) || " ".equals(changeText)) {
                            tipMenu.setVisible(false);
                            return;
                        }
                        List<String> items = tipService.getTip(changeText.replace("\n", ""));
                        for (String item : items) {
                            JMenuItem menuItem = new JMenuItem(item);
                            // 被选中时，输入到textarea中
                            menuItem.addActionListener(e -> {
                                System.out.println(e.getActionCommand());
                                textArea.append(e.getActionCommand());
                            });
                            tipMenu.add(menuItem);
                            tipMenu.addKeyListener(new KeyListener() {
                                @Override
                                public void keyTyped(KeyEvent e) {

                                }

                                // 按下键时候进行popmenu选中
                                @Override
                                public void keyPressed(KeyEvent e) {
                                    System.out.println("键盘:" + e);
                                }

                                @Override
                                public void keyReleased(KeyEvent e) {

                                }
                            });
                        }
                        tipMenu.show(textArea, (int) rectangle.getX(), (int) rectangle.getY() + rectangle.height);
                        tipMenu.setFocusable(false);
                    }
                }
            }

            private void showPopTipsForDelete(String changeText, int offset) {
                // 非全文加载时显示提示
                if (offset != 0 || !changeText.startsWith(" ")) {
                    Rectangle rectangle = null;
                    try {
                        rectangle = textArea.modelToView(textArea.getCaretPosition() - 1);
                    } catch (BadLocationException ex) {
                        ex.printStackTrace();
                        tipMenu.setVisible(false);
                    }
                    if (rectangle != null) {
                        tipMenu.removeAll();
                        if ("\n".equals(changeText) || " ".equals(changeText) || StringUtil.isEmpty(changeText)) {
                            tipMenu.setVisible(false);
                            return;
                        }
                        List<String> items = tipService.getTip(changeText.replace("\n", ""));
                        for (String item : items) {
                            tipMenu.add(new JMenuItem(item));
                        }
                        tipMenu.show(textArea, (int) rectangle.getX(), (int) rectangle.getY() + rectangle.height);
                        tipMenu.setFocusable(false);
                    }
                }
            }
        });

        textArea.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {

            }

            @Override
            public void keyPressed(KeyEvent e) {
                System.out.println(e.toString());
                System.out.println("keyPressed" + e.toString());
                // CTRL+C  : https://blog.csdn.net/withiter/article/details/17247617
                if (e.getModifiers() == 2 && e.getKeyCode() == 67) {
                    copy();
                }
                // CTRL+V
                if (e.getModifiers() == 2 && e.getKeyCode() == 86) {
                    v();
                }
                // CTRL + X
                if (e.getModifiers() == 2 && e.getKeyCode() == 88) {
                    cut();
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {

            }
        });
    }

    private void v() {
        Transferable contents = clipboard.getContents(this);
        DataFlavor flavor = DataFlavor.stringFlavor;
        if (contents.isDataFlavorSupported(flavor)) {
            try {
                String str = (String) contents.getTransferData(flavor);
                textArea.insert(str, textArea.getCaretPosition());
//                        textArea.append(str);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    private void copy() {
        String tempText = textArea.getSelectedText();
        StringSelection editText = new StringSelection(tempText);
        clipboard.setContents(editText, null);
    }

    private void cut() {
        copy();
        int start = textArea.getSelectionStart();
        int end = textArea.getSelectionEnd();
        textArea.replaceRange("", start, end); //从Text1中删除被选取的文本。
    }

    public EditPanel setText(String text) {
        textArea.setText(text);
        return this;
    }

    public String getText() {
        return textArea.getText();
    }

    public void append(String msg) {
        textArea.append(msg + "\n");
    }

    public void appendAndRefresh(String msg) {
        textArea.append(msg);
        textArea.setCaretPosition(textArea.getDocument().getLength());
    }

    public JTextArea getTextArea() {
        return this.textArea;
    }

    /**
     * 刷新光标位置
     */
    public void refreshCaretPosition() {
        textArea.setCaretPosition(textArea.getDocument().getLength());
    }

    public EditPanel addYxKeyListener(KeyListener l) {
        textArea.addKeyListener(l);
        // 实现拖动文件至文本窗口显示  https://blog.csdn.net/java_faep/article/details/53523401
        textArea.setTransferHandler(new TransferHandler() {

            private static final long serialVersionUID = 1L;

            @Override
            public boolean importData(JComponent comp, Transferable t) {
                try {
                    Object o = t.getTransferData(DataFlavor.javaFileListFlavor);

                    String filepath = o.toString();
                    if (filepath.startsWith("[")) {
                        filepath = filepath.substring(1);
                    }
                    if (filepath.endsWith("]")) {
                        filepath = filepath.substring(0, filepath.length() - 1);
                    }
                    System.out.println(filepath);
                    textArea.setText(FileUtil.readText(new File(filepath)));
                    return true;
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return false;
            }

            @Override
            public boolean canImport(JComponent comp, DataFlavor[] flavors) {
                for (int i = 0; i < flavors.length; i++) {
                    if (DataFlavor.javaFileListFlavor.equals(flavors[i])) {
                        return true;
                    }
                }
                return false;
            }
        });
        return this;
    }


}
